No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

82 líneas
2.6 KiB

  1. /**
  2. * 服务端 API 代理 —— 将 /api/** 请求转发到 ThinkJS 后端
  3. *
  4. * 对齐 ai_uniapp_v2 H5 端的 manifest.json devServer.proxy 行为:
  5. * /api/user/info → https://api.jiefuku.com/user/info
  6. *
  7. * 用途:
  8. * 1. 避免浏览器跨域
  9. * 2. 服务端转发自动携带 cookie,保持登录态
  10. *
  11. * 环境变量 API_BASE 可覆盖目标地址(生产环境指向 https://api.aionline.cc)
  12. */
  13. export default defineEventHandler(async (event) => {
  14. const apiBase = process.env.API_BASE || 'http://192.168.31.168:16888'
  15. // 去掉 /api 前缀,得到真实后端路径
  16. let path = event.path.replace(/^\/api/, '') || '/'
  17. if (!path.startsWith('/')) path = '/' + path
  18. const method = event.method
  19. const url = apiBase + path
  20. const headers = {}
  21. // 转发用户 cookie(保持登录态)
  22. const cookie = event.headers.get('cookie')
  23. if (cookie) {
  24. headers.cookie = cookie
  25. }
  26. // 透传客户端的 Content-Type(multipart/form-data 上传需要)
  27. const contentType = event.headers.get('content-type')
  28. if (contentType) {
  29. headers['content-type'] = contentType
  30. }
  31. // 透传签名的 header(nonce / timestr / token)
  32. const clientNonce = event.headers.get('nonce')
  33. const clientTimestr = event.headers.get('timestr')
  34. const clientToken = event.headers.get('token')
  35. if (clientNonce) headers.nonce = clientNonce
  36. if (clientTimestr) headers.timestr = clientTimestr
  37. if (clientToken) headers.token = clientToken
  38. const fetchOptions = { method, headers }
  39. // GET: 查询参数
  40. const query = getQuery(event)
  41. const queryStr = new URLSearchParams(query).toString()
  42. const fullUrl = queryStr ? url + '?' + queryStr : url
  43. // POST: 请求体
  44. if (method === 'POST') {
  45. const body = await readBody(event)
  46. if (body && typeof body === 'object') {
  47. // 如果是 FormData 上传(multipart),直接透传原始 body
  48. if (contentType && contentType.includes('multipart/form-data')) {
  49. // multipart 请求的 body 需要特殊处理,直接用原始 buffer
  50. const rawBody = await readRawBody(event)
  51. if (rawBody) {
  52. fetchOptions.body = rawBody
  53. // 保留原始 boundary
  54. fetchOptions.headers = { ...fetchOptions.headers, 'content-type': contentType }
  55. }
  56. } else {
  57. fetchOptions.body = new URLSearchParams(body).toString()
  58. }
  59. }
  60. }
  61. try {
  62. return await $fetch(fullUrl, fetchOptions)
  63. } catch (error) {
  64. console.error('[Server Proxy Error]', url, error.message)
  65. return {
  66. code: 1000,
  67. data: null,
  68. msg: '服务器代理请求失败',
  69. }
  70. }
  71. })